from __future__ import absolute_import

import logging
import traceback
import redis
from datetime import datetime
from urllib.parse import urlparse
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import DisallowedHost
from django.utils.http import is_same_domain
from django.http import QueryDict
from django.middleware.csrf import _sanitize_token, _compare_masked_tokens,\
    REASON_NO_REFERER, REASON_MALFORMED_REFERER, \
    REASON_INSECURE_REFERER, REASON_BAD_REFERER, REASON_NO_CSRF_COOKIE, REASON_BAD_TOKEN, CsrfViewMiddleware

from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework import status


from huaweicloudsdkcore.auth.credentials import BasicCredentials
from huaweicloudsdkcore.http.http_config import HttpConfig
from huaweicloudsdkces.v2 import CesClient

from conf.conf import ces_ak, ces_sk, ces_project_id, ces_endpoint
from ploto.settings.dev import REDIS_HOST, REDIS_PASSWORD, REDIS_PORT

logger = logging.getLogger(__name__)


def record_ip(func):
    def wrapper(obj, request, *args, **kwargs):
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            client_ip = request.META['HTTP_X_FORWARDED_FOR']
            client_ip = client_ip.split(",")[0]
        else:
            try:
                client_ip = request.META['REMOTE_ADDR']
            except Exception as e:
                client_ip = ''
                logger.error("failed to resolve client_ip, "
                             "exception： %s, %s", repr(e), traceback.format_exc())
                logger.error("Unknow IP access %s", request.META['PATH_INFO'])
        return func(obj, request, *args, **kwargs)

    return wrapper


# 为request请求鉴权
def auth_request(view_func):
    csrf_view_middleware = CsrfViewMiddleware()

    # 校验token是否正确
    def auth_safety_method(obj, request, *args, **kwargs):
        if request.method not in settings.UN_SAFETY_METHODS:
            if request.is_secure():
                referer = request.META.get('HTTP_REFERER')
                if referer is None:
                    csrf_view_middleware._reject(request, REASON_NO_REFERER)
                    return Response({'details': REASON_NO_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                referer = urlparse(referer)

                # Make sure we have a valid URL for Referer.
                if '' in (referer.scheme, referer.netloc):
                    csrf_view_middleware._reject(request, REASON_MALFORMED_REFERER)
                    return Response({'details': REASON_MALFORMED_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                # Ensure that our Referer is also secure.
                if referer.scheme != 'https':
                    csrf_view_middleware._reject(request, REASON_INSECURE_REFERER)
                    return Response({'details': REASON_INSECURE_REFERER}, status=status.HTTP_401_UNAUTHORIZED)

                # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match
                # match on host:port. If not, obey the cookie rules (or those
                # for the session cookie, if CSRF_USE_SESSIONS).
                good_referer = (
                    settings.SESSION_COOKIE_DOMAIN
                    if settings.CSRF_USE_SESSIONS
                    else settings.CSRF_COOKIE_DOMAIN
                )
                if good_referer is not None:
                    server_port = request.get_port()
                    if server_port not in ('443', '80'):
                        good_referer = '%s:%s' % (good_referer, server_port)
                else:
                    try:
                        # request.get_host() includes the port.
                        good_referer = request.get_host()
                    except DisallowedHost:
                        pass

                # Create a list of all acceptable HTTP referers, including the
                # current host if it's permitted by ALLOWED_HOSTS.
                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                if good_referer is not None:
                    good_hosts.append(good_referer)

                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                    reason = REASON_BAD_REFERER % referer.geturl()
                    csrf_view_middleware._reject(request, reason)
                    return Response({'details': reason}, status=status.HTTP_401_UNAUTHORIZED)

            # Access csrf_token via self._get_token() as rotate_token() may
            # have been called by an authentication middleware during the
            # process_request() phase.
            csrf_token = csrf_view_middleware._get_token(request)
            if csrf_token is None:
                # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
                # and in this way we can avoid all CSRF attacks, including login
                # CSRF.
                csrf_view_middleware._reject(request, REASON_NO_CSRF_COOKIE)
                return Response({'details': REASON_NO_CSRF_COOKIE}, status=status.HTTP_401_UNAUTHORIZED)

            # Check non-cookie token for match.
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                except OSError:
                    pass
            if request_csrf_token == "":
                # Fall back to X-CSRFToken, to make things easier for AJAX,
                # and possible for PUT/DELETE.
                request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

            request_csrf_token = _sanitize_token(request_csrf_token)
            if not _compare_masked_tokens(request_csrf_token, csrf_token):
                csrf_view_middleware._reject(request, REASON_BAD_TOKEN)
                return Response({'details': REASON_BAD_TOKEN}, status=status.HTTP_401_UNAUTHORIZED)

        request.csrf_processing_done = True
        return view_func(obj, request, *args, **kwargs)

    return auth_safety_method


def get_parameter_dic(request):
    if not isinstance(request, Request):
        return {}

    query_params = request.query_params
    if isinstance(query_params, QueryDict):
        query_params = query_params.dict()
    result_data = request.data
    if isinstance(result_data, QueryDict):
        result_data = result_data.dict()

    if query_params != {}:
        return query_params
    else:
        return result_data


def scenario_conversion_main_scene(scenario_id):
    if scenario_id in ('follow_big_car', 'follow_and_stop'):
        value = "follow_car"
    elif scenario_id in ('cut_in-1', 'cut_in-2', 'overtake'):
        value = "cut_in"
    else:
        value = "confluence"
    return value


# save cache
def set_cache(value, key, timeout=10 * 60):
    cache.set(key, value, timeout)


# get cache
def get_cache(*keys):
    key = ""
    for t in keys:
        key.join(t)
    value = cache.get(key)
    return value


def fill_filter_data(params):
    all_keys_dict = {
        "__icontains": ["name", "car_id", "area", "tag", "data_type", "storage_type"],
        "__range": ["collect_time"]
    }
    filter_data = {"is_delete": 0}
    for key, values in all_keys_dict.items():
        for query_key in values:
            value = params.get(query_key, '')
            if value:
                if key == "__range":
                    dt_from = datetime.strptime(value.split("-")[0], "%Y/%m/%d %H:%M:%S")
                    # 查询的时候默认date_to+86399(当天的23:59:59)
                    dt_to = datetime.strptime(value.split("-")[1], '%Y/%m/%d %H:%M:%S')
                    filter_data[query_key + key] = (dt_from, dt_to)
                else:
                    filter_data[query_key + key] = value
    return filter_data


def set_header(headers, storage_class):
    if storage_class == 0:
        headers.storageClass = 'STANDARD'
    elif storage_class == 1:
        headers.storageClass = 'WARM'
    elif storage_class == 2:
        headers.storageClass = 'COLD'


def get_ces_client(ak, sk, endpoint, project_id):
    config = HttpConfig.get_default_config()
    config.ignore_ssl_verification = True
    credentials = BasicCredentials(ak, sk, project_id)
    new_ces_client = CesClient.new_builder() \
        .with_http_config(config) \
        .with_credentials(credentials) \
        .with_endpoint(endpoint) \
        .build()
    return new_ces_client


ces_client = get_ces_client(ces_ak, ces_sk, ces_endpoint, ces_project_id)


def check_session(sessionid):
    # 检测session是否过期
    r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, db=9)
    prefix = ':1:django.contrib.sessions.cache'
    check_key = prefix + str(sessionid)
    resp = r.keys(check_key)
    if resp is None:
        return False
    # 还存在就续3600s
    r.expire(check_key, 3600)
    return True
